#include "formulatest.h"

bool FormulaTest::run() {
    short count=0;

    if (!FormulaTest::constructorTest())
        std::cout << "ERROR " << ++count << " FormulaTest::constructorTest() faild!" << std::endl;
    if (!FormulaTest::toStringTest())
        std::cout << "ERROR " << ++count << " FormulaTest::toStringTest() faild!" << std::endl;
    if (!FormulaTest::evaluationTestRandomFormula())
        std::cout << "ERROR " << ++count << " FormulaTest::evaluationTestRandomFormula() faild!" << std::endl;
    if (!FormulaTest::evaluationTestConstructedFormula())
        std::cout << "ERROR " << ++count << " FormulaTest::evaluationTestConstructedFormula() faild!" << std::endl;
    if (!FormulaTest::mutateTest())
        std::cout << "ERROR " << ++count << " FormulaTest::mutateTest() faild!" << std::endl;
    if (!FormulaTest::deleteAndAddToFormulaTest())
        std::cout << "ERROR " << ++count << " FormulaTest::deleteAndAddToFormulaTest() faild!" << std::endl;
    if (!FormulaTest::mutateAddNewElementAtIteratorPositionTest())
        std::cout << "ERROR " << ++count << " FormulaTest::mutateAddNewElementAtIteratorPositionTest() faild!" << std::endl;
    if (!FormulaTest::mutateDeleteElementAtIteratorPositionTest())
        std::cout << "ERROR " << ++count << " FormulaTest::mutateDeleteElementAtIteratorPositionTest() faild!" << std::endl;
    if (!FormulaTest::mutateElementMutateTest())
        std::cout << "ERROR " << ++count << " FormulaTest::mutateElementMutateTest() faild!" << std::endl;
    if (!FormulaTest::toHumanReadeableStringTest())
        std::cout << "ERROR " << ++count << " FormulaTest::toHumanReadeableStringTest() faild!" << std::endl;

    return count==0;
}

bool FormulaTest::constructorTest() {
    Formula *testFormula = new Formula();
    delete testFormula;
    return true;
}

bool FormulaTest::toStringTest() {
    Formula *testFormula = new Formula();
    LinkedList<FormulaElement>& felist = testFormula->getListOfFormulaElements();
    felist.addAtStart(*(new RealNumber(749.12)));
    felist.addAtStart(*(new RealNumber(843.18)));
    felist.addAtEnd(*(new RealPlus()));
    felist.addAtEnd(*(new RealNumber(343.234)));
    felist.addAtEnd(*(new RealDivide()));
    felist.addAtEnd(*(new RealVariable('n',11)));
    felist.addAtEnd(*(new RealMultiplication()));
    std::string& temp = testFormula->toString();
    assert(!temp.compare("843.18 749.12 + 343.234 / n *"));
    delete &temp;
    delete testFormula;
    return true;
}

bool FormulaTest::evaluationTestRandomFormula() {
    unsigned int size = 11;
    Formula *testFormula = FormulaFactory::createNewFormula(size ,false);
    Input input;
    input.createPrimeInput(6);
    InputIterator& inputIterator = input.getNewIterator();
    testFormula->evaluate(inputIterator);
    delete &inputIterator;
    delete testFormula;
    return true;
}

bool FormulaTest::evaluationTestConstructedFormula() {
    Formula *testFormula = new Formula();
    LinkedList<FormulaElement>& list = testFormula->getListOfFormulaElements();
    list.addAtEnd(*(new RealNumber(78)));
    list.addAtEnd(*(new RealNumber(67)));
    list.addAtEnd(*(new RealNumber(56)));
    list.addAtEnd(*(new RealNumber(45)));
    list.addAtEnd(*(new RealPlus()));
    list.addAtEnd(*(new RealMinus()));
    list.addAtEnd(*(new RealNumber(35)));
    list.addAtEnd(*(new RealPlus()));
    list.addAtEnd(*(new RealPow()));
    list.addAtEnd(*(new RealNumber(2)));
    list.addAtEnd(*(new RealDivide()));
    list.addAtEnd(*(new RealVariable('n', 0)));
    list.addAtEnd(*(new RealPlus()));

    Input input;
    input.createPrimeInput(2);
    InputIterator& inputIterator = input.getNewIterator();
    testFormula->evaluate(inputIterator);

    assert(testFormula->getFitness()==76);

    delete &inputIterator;
    delete testFormula;
    return true;
}

bool FormulaTest::mutateTest() {
    unsigned int size = 11;
    Formula *testFormula = FormulaFactory::createNewFormula(size ,false);
    Input input;
    input.createPrimeInput(6);
    InputIterator& inputIterator = input.getNewIterator();

    for(int i=20; --i;) {
        testFormula->mutate();
//        std::cout<<(testFormula->toString())<<"\n";
    }

    testFormula->evaluate(inputIterator);
    delete &inputIterator;
    delete testFormula;
    return true;
    return false;
}

bool FormulaTest::deleteAndAddToFormulaTest() {
    Formula *testFormula = new Formula();
    LinkedList<FormulaElement>& list = testFormula->getListOfFormulaElements();
    list.addAtEnd(*(new RealNumber(78)));
    list.addAtEnd(*(new RealNumber(67)));
    list.addAtEnd(*(new RealNumber(56)));
    list.addAtEnd(*(new RealNumber(45)));
    list.addAtEnd(*(new RealPlus()));
    list.addAtEnd(*(new RealMinus()));
    list.addAtEnd(*(new RealPlus()));

    list.resetIteratorPosition();
    list.iteratorGetNext();
    list.iteratorGetNext();
    list.deleteAtIteratorPosition();
    list.addAtIteratorPosition(*(new RealNumber(56)));

    Input input;
    input.createPrimeInput(1);
    InputIterator& inputIterator = input.getNewIterator();
    testFormula->evaluate(inputIterator);

    assert(testFormula->getFitness()==42);

    delete &inputIterator;
    delete testFormula;
    return true;
}

bool FormulaTest::mutateAddNewElementAtIteratorPositionTest() {
    unsigned int size = 11;
    Formula *testFormula = FormulaFactory::createNewFormula(size ,false);
    Input input;
    input.createPrimeInput(6);
    InputIterator& inputIterator = input.getNewIterator();

    LinkedList<FormulaElement>& elements=testFormula->getListOfFormulaElements();

    int chance=5;
    int level=0;
    elements.resetIteratorPosition();
    testFormula->mutateAddNewElementAtIteratorPosition(chance, level, elements.iteratorPositionIsCloseToStart());
    testFormula->mutateAddNewElementAtIteratorPosition(++chance, level, elements.iteratorPositionIsCloseToStart());
    testFormula->mutateAddNewElementAtIteratorPosition(--chance, level, elements.iteratorPositionIsCloseToStart());
    testFormula->mutateAddNewElementAtIteratorPosition(--chance, level, elements.iteratorPositionIsCloseToStart());
    testFormula->mutateAddNewElementAtIteratorPosition(--chance, level, elements.iteratorPositionIsCloseToStart());
    testFormula->mutateAddNewElementAtIteratorPosition(--chance, level, elements.iteratorPositionIsCloseToStart());
    testFormula->mutateAddNewElementAtIteratorPosition(++chance, level, elements.iteratorPositionIsCloseToStart());
    testFormula->mutateAddNewElementAtIteratorPosition(++chance, level, elements.iteratorPositionIsCloseToStart());
    testFormula->mutateAddNewElementAtIteratorPosition(++chance, level, elements.iteratorPositionIsCloseToStart());
    testFormula->mutateAddNewElementAtIteratorPosition(++chance, level, elements.iteratorPositionIsCloseToStart());
    testFormula->mutateAddNewElementAtIteratorPosition(++chance, level, elements.iteratorPositionIsCloseToStart());
    testFormula->mutateAddNewElementAtIteratorPosition(++chance, level, elements.iteratorPositionIsCloseToStart());
    testFormula->mutateAddNewElementAtIteratorPosition(++chance, level, elements.iteratorPositionIsCloseToStart());
    testFormula->mutateAddNewElementAtIteratorPosition(++chance, level, elements.iteratorPositionIsCloseToStart());
    testFormula->mutateBringLevelBackToZero(level);

    testFormula->evaluate(inputIterator);
    delete &inputIterator;
    delete testFormula;
    return true;
}

bool FormulaTest::mutateDeleteElementAtIteratorPositionTest() {
    unsigned int size = 11;
    Formula *testFormula = FormulaFactory::createNewFormula(size ,false);
    Input input;
    input.createPrimeInput(6);
    InputIterator& inputIterator = input.getNewIterator();

    int chance=5;
    int level=0;
    testFormula->getListOfFormulaElements().resetIteratorPosition();
    testFormula->mutateDeleteElementAtIteratorPosition(chance, level);
    testFormula->mutateDeleteElementAtIteratorPosition(chance, level);
    testFormula->mutateAddNewElementAtIteratorPosition(chance, level, testFormula->getListOfFormulaElements().iteratorPositionIsCloseToStart());
    testFormula->mutateDeleteElementAtIteratorPosition(chance, level);
    testFormula->mutateDeleteElementAtIteratorPosition(chance, level);
    testFormula->mutateDeleteElementAtIteratorPosition(chance, level);
    testFormula->mutateDeleteElementAtIteratorPosition(chance, level);
    testFormula->mutateDeleteElementAtIteratorPosition(chance, level);
    testFormula->mutateDeleteElementAtIteratorPosition(chance, level);
    testFormula->mutateDeleteElementAtIteratorPosition(chance, level);
    testFormula->mutateBringLevelBackToZero(level);

    testFormula->evaluate(inputIterator);
    delete &inputIterator;
    delete testFormula;
    return true;
}

bool FormulaTest::mutateElementMutateTest() {
    unsigned int size = 11;
    Formula *testFormula = FormulaFactory::createNewFormula(size ,false);
    Input input;
    input.createPrimeInput(6);
    InputIterator& inputIterator = input.getNewIterator();

    testFormula->getListOfFormulaElements().resetIteratorPosition();
    while(testFormula->getListOfFormulaElements().iteratorHasNext())
        testFormula->mutateElementMutate();
//    testFormula->mutateBringLevelBackToZero(level);

    testFormula->evaluate(inputIterator);
    delete &inputIterator;
    delete testFormula;
    return true;
}

bool FormulaTest::toHumanReadeableStringTest() {
    unsigned int& length = *(new unsigned int(15));
    Formula& formula = *(FormulaFactory::createNewFormula(length,false));
    std::string& humanString = formula.toHumanString();
    std::string& toString = formula.toString();
//    std::cout   << std::endl
//                << humanString
//                << std::endl
//                << toString
//                << std::endl;
    delete &humanString;
    delete &toString;
    delete &length;
    delete &formula;
    return true;
}
